#include "StdAfx.h"
#include "RetrieveUSBDeviceInfo.h"
#include "E:\testcode\DuanhongSDK\Common\DH_Common\GeneralFucs.h"
#include "C:\WinDDK\7600.16385.1\inc\api\usb.h"
#include "C:\WinDDK\7600.16385.1\inc\ddk\usbscan.h"
#include <winioctl.h>

CRetrieveUSBDeviceInfo::CRetrieveUSBDeviceInfo(void)
{
}

CRetrieveUSBDeviceInfo::~CRetrieveUSBDeviceInfo(void)
{
}

BOOL CRetrieveUSBDeviceInfo::GetSpecificUSBDevInfo(PDEV_BROADCAST_DEVICEINTERFACE_A pDeviceInterface, DevOutputInfo & DevOutInformation)
{	
	if (NULL == pDeviceInterface)
	{
		return FALSE;
	}
	if (strlen(pDeviceInterface->dbcc_name) <= 4)
	{
		return FALSE;
	}

	//note: we should develop unicode application especially for Windows Service. 
	std::string strDevId_A = pDeviceInterface->dbcc_name + 4;
	size_t idx = strDevId_A.rfind('#');
	if (idx == std::string::npos)
	{
		return FALSE;
	}

	strDevId_A = strDevId_A.substr(0, idx);

	idx = strDevId_A.find('#');;
	if (idx == std::string::npos)
	{
		return FALSE;
	}
	replace(strDevId_A.begin(), strDevId_A.end(), '#', '\\');

#ifdef _UNICODE
	std::wstring strDevId = DHCOMMON::CGeneralFucs::str2wstr(strDevId_A);

#else
	std::string strDevId = strDevId_A;

#endif

	DWORD dwFlag =  DIGCF_DEVICEINTERFACE | DIGCF_PRESENT;
	HDEVINFO hDevClassInfo = SetupDiGetClassDevs(&pDeviceInterface->dbcc_classguid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
	if(hDevClassInfo == INVALID_HANDLE_VALUE)
	{ 
		return FALSE;
	}

	BOOL bRet = TRUE;
	SP_DEVINFO_DATA spDevInfoData;
	spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);

	SP_DEVICE_INTERFACE_DATA spDevInterfaceData;
	spDevInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);

	DWORD dwSize = 0;
	PSP_INTERFACE_DEVICE_DETAIL_DATA pDeviceDetailData = NULL;

	USB_DEVICE_DESCRIPTOR data;
	USBSCAN_GET_DESCRIPTOR descriptor;
	DWORD length;	

	//if (! FindDevice(hDevClassInfo, strDevId.c_str(), spDevInfoData) ) 
	//{
	//	bRet = FALSE;
	//	goto exit1;
	//}

	int nMemberIndex = 0;
	for (nMemberIndex = 0; TRUE; nMemberIndex++) 
	{
		bRet = SetupDiEnumDeviceInterfaces (hDevClassInfo, NULL,(LPGUID)&pDeviceInterface->dbcc_classguid, nMemberIndex,
			&spDevInterfaceData);
		if (!bRet)
		{
			break;
		}

		bRet  = SetupDiGetDeviceInterfaceDetail(hDevClassInfo, &spDevInterfaceData, NULL, 0, &dwSize, NULL);                  
		if (!bRet)
		{
			DWORD dwError = ::GetLastError();
			if (dwError == ERROR_INSUFFICIENT_BUFFER)//yes, it's what we want.
			{
				// Allocate memory for the device detail buffer. 
				pDeviceDetailData= (PSP_INTERFACE_DEVICE_DETAIL_DATA)malloc(dwSize);
				if (pDeviceDetailData == NULL) 
				{ 
					bRet = FALSE;
					goto exit1; 
				}
				pDeviceDetailData->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
				bRet = SetupDiGetDeviceInterfaceDetail(hDevClassInfo, &spDevInterfaceData, pDeviceDetailData, dwSize, NULL, &spDevInfoData);
				if (!bRet)
				{ 
					goto exit1;
				}

				DWORD dwSize = 0 ;
				TCHAR szBuf[MAX_PATH];
				bRet = SetupDiGetDeviceInstanceId(hDevClassInfo, &spDevInfoData, szBuf, sizeof(szBuf), &dwSize);
				if ( ! bRet) 
				{
					goto exit1;
				} 
				if ( _tcsicmp(strDevId.c_str(), szBuf) == 0)
				{
					// OK, device found.
					HANDLE hfile = ::CreateFile(pDeviceDetailData->DevicePath,GENERIC_WRITE | GENERIC_READ,
						FILE_SHARE_WRITE|FILE_SHARE_READ,
						NULL,
						CREATE_ALWAYS,
						FILE_ATTRIBUTE_NORMAL,
						NULL
						);
					if (INVALID_HANDLE_VALUE != hfile)
					{				
						descriptor.DescriptorType = USB_DEVICE_DESCRIPTOR_TYPE;					
						bRet = ::DeviceIoControl(hfile,IOCTL_GET_USB_DESCRIPTOR ,&descriptor,sizeof(descriptor),&data,sizeof(data),&length,NULL);
						
						if (!bRet)
						{
							dwError = ::GetLastError();
						}
					}

					break;
				}
		

				if (NULL != pDeviceDetailData)
				{
					free(pDeviceDetailData);
					pDeviceDetailData = NULL;
				}

			}
			else
			{
				bRet = FALSE;
				break;
			}
		}


	}




exit1:
	//do remember to call SetupDiDestroyDeviceInfoList;
	SetupDiDestroyDeviceInfoList(hDevClassInfo);
	if (NULL != pDeviceDetailData)
	{
		free(pDeviceDetailData);
		pDeviceDetailData = NULL;
	}
	return bRet;
}

BOOL CRetrieveUSBDeviceInfo::FindDevice( HDEVINFO hDevInfo, LPCTSTR pszDevId, SP_DEVINFO_DATA& spDevInfoData )
{
	if (hDevInfo == NULL || pszDevId == NULL)
	{
		return E_INVALIDARG;
	}

	spDevInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
	for(int i=0; SetupDiEnumDeviceInfo(hDevInfo, i, &spDevInfoData); i++) 
	{
		DWORD dwSize = 0 ;
		TCHAR szBuf[MAX_PATH];

		if ( !SetupDiGetDeviceInstanceId(hDevInfo, &spDevInfoData, szBuf, sizeof(szBuf), &dwSize) ) 
		{
			_tprintf_s(_T("SetupDiGetDeviceInstanceId(): %s"), _com_error(GetLastError()).ErrorMessage());
			return FALSE;
		} 
		if ( _tcsicmp(pszDevId, szBuf) == 0)
		{
			// OK, device found
			return TRUE;
		}
	}
	return FALSE;
}